<?php
require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'wsr.inc.php';
require_once WSR_DIR . DIRECTORY_SEPARATOR . 'tests/supercompare.inc.php';
require_once WSR_DIR . 'rules.class.php';
require_once MORIARTY_DIR . "simplegraph.class.php";
require_once MORIARTY_ARC_DIR . 'ARC2.php';
//require_once MORIARTY_ARC_DIR . 'serializers' . DIRECTORY_SEPARATOR . 'ARC2_TurtleSerializer.php';


class RulesTest extends PHPUnit_Framework_TestCase {
	
	function makeTestRuleEmployment() {
		return new Rule('?person a eg:Employee', 
                  '?person a foaf:Person',
                  array( 'namespaces' => array( 'eg'   => 'http://www.example.com/', 
                                                'foaf' => 'http://xmlns.com/foaf/0.1/' )) );
	}
	
	function makeTestGraphEmployment() {
		return array( 'Nad' => array( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' 
									         => array( array( 'type' => 'uri', 'value' => 'http://www.example.com/Employee' ) ),
									  'http://www.example.com/Employed_in' 
									         => array( array( 'type' => 'uri', 'value' => 'http://www.talis.com/' ) )
									),
					  'Alan' => array( 'http://www.example.com/Employed_in' 
									         => array( array( 'type' => 'uri', 'value' => 'http://www.comp.lancs.ac.uk/' ) )
									)
					   );
	}

	function makeTestPatterns() {
		$pat1 = array(
					'type' => 'triple',
					's' => 'person',
					'p' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
					'o' => 'http://www.example.com/Employee',
					's_type' => 'var',
					'p_type' => 'uri',
					'o_type' => 'uri',
					'o_datatype' => '',
					'o_lang' => '',
				);
		
		$pat2 = array(
					'type' => 'triple',
					's' => 'person',
					'p' => 'http://www.example.com/Employed_in',
					'o' => 'employer',
					's_type' => 'var',
					'p_type' => 'uri',
					'o_type' => 'var',
					'o_datatype' => '',
					'o_lang' => '',
				);
		return array( $pat1, $pat2 );
	}

	function makeTestBindings() {
		$b = array();
		$b['bind1'] = array( 'abc'=> array( 'type' => 'uri', 'value' => 'http://www.example.com/def' ) );
		$b['bind2'] = array( 'xyz'=> array( 'type' => 'literal', 'value' => 'XYZ' ) );
		$b['bind3'] = array( 'abc'=> array( 'type' => 'uri', 'value' => 'http://www.example.com/def' ),
						'xyz'=> array( 'type' => 'literal', 'value' => 'XYZ' )  );
		$b['bind4'] = array( 'abc'=> array( 'type' => 'uri', 'value' => 'http://www.example.com/nop' ) );
		$b['Nad_p']	= array(  'person'=> array( 'type' => 'uri', 'value' => 'Nad' )
							);
		$b['Nad_ep']	= array(	'person'=> array( 'type' => 'uri', 'value' => 'Nad' ),
								'employer'=> array( 'type' => 'uri', 'value' => 'http://www.talis.com/' )
							);
		$b['Nad_e']	= array(	'employer'=> array( 'type' => 'uri', 'value' => 'http://www.talis.com/' )
							);
		$b['Alan_ep']	= array(	'person'=> array( 'type' => 'uri', 'value' => 'Alan' ),
								'employer'=> array( 'type' => 'uri', 'value' => 'http://www.comp.lancs.ac.uk/' )
							);
		$b['Alan_e']	= array(	'employer'=> array( 'type' => 'uri', 'value' => 'http://www.comp.lancs.ac.uk/' )
							);
		return $b;
	}
	
	
	
	var $sharedFixture;
	protected function setUp()
    {
        $this->sharedFixture = array("test stuff here");
    }
 
    protected function tearDown()
    {
        $this->sharedFixture = NULL;
    }
	
	function test_rule_contruction() {
		$rule = $this->makeTestRuleEmployment();
		$expected_lhs = array( array(
								'type' => 'triple',
								's' => 'person',
								'p' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
								'o' => 'http://www.example.com/Employee',
								's_type' => 'var',
								'p_type' => 'uri',
								'o_type' => 'uri',
								'o_datatype' => '',
								'o_lang' => '',
							)  );
		$expected_rhs = array( array(
								'type' => 'triple',
								's' => 'person',
								'p' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
								'o' => 'http://xmlns.com/foaf/0.1/Person',
								's_type' => 'var',
								'p_type' => 'uri',
								'o_type' => 'uri',
								'o_datatype' => '',
								'o_lang' => '',
							)  );
		$expected_wildcards = array( 'person' );
		$this->assertEquals( $rule->lhs_parsed, $expected_lhs, "LHS not parsed correctly" );
		$this->assertEquals( $rule->rhs_parsed, $expected_rhs, "RHS not parsed correctly" );
		$this->assertEquals( $rule->lhs_wildcards, $expected_wildcards, "LHS wildcards incorrect" );
		$this->assertEquals( $rule->rhs_wildcards, $expected_wildcards, "RHS wildcards incorrect" );
	}
	
	function test_runner_match_one() {
		$runner = new RuleRunner();
				
		$bindings = $this->makeTestBindings();
		$bind1		=  $bindings['bind1'];
		$bind2		=  $bindings['bind2'];
		$bind3		=  $bindings['bind3'];
		$bind4		=  $bindings['bind4'];

		
		$bound = $runner->match_one( 'abc', 'var', 'http://www.example.com/def', 'uri', array() );
		$this->assertEquals( $bound, $bind1, "unset variable binding" );
		
		$bound = $runner->match_one( 'abc', 'var', 'http://www.example.com/def', 'uri', $bind2 );
		$this->assertEquals( $bound, $bind3, "unset variable extending binding" );
		
		$bound = $runner->match_one( 'abc', 'var', 'http://www.example.com/def', 'uri', $bind1 );
		$this->assertEquals( $bound, $bind1, "set variable matches" );
		
		$bound = $runner->match_one( 'abc', 'var', 'http://www.example.com/xyz', 'uri', $bind1 );
		$this->assertEquals( $bound, false, "set variable doesn't match" );

		$bound = $runner->match_one( 'abc', 'var', 'http://www.example.com/def', 'literal', $bind1 );
		$this->assertEquals( $bound, false, "set variable type doesn't match" );

		$bound = $runner->match_one( 'http://www.example.com/def', 'uri', 'http://www.example.com/def', 'uri', $bind1 );
		$this->assertEquals( $bound, $bind1, "non variables match" );

		$bound = $runner->match_one( 'http://www.example.com/def', 'uri', 'http://www.example.com/xyz', 'uri', $bind1 );
		$this->assertEquals( $bound, false, "non variables do not match" );

	}
	
	function test_runner_match() {
		$graph = $this->makeTestGraphEmployment();
		$runner = new RuleRunner($graph);
		
		list($pat1,$pat2) = $this->makeTestPatterns();
		
		$bindings = $this->makeTestBindings();
		$bind1		=  $bindings['bind1'];
		$bind_Nad_p	=  array_merge( $bind1, $bindings['Nad_p'] );
		$bind_Nad_ep	=  array_merge( $bind1, $bindings['Nad_ep'] );
		$bind_Alan_ep	=  array_merge( $bind1, $bindings['Alan_ep'] );
		
		$bound = $runner->match( $pat1, $bind1 );
		$this->assertEquals( $bound, array($bind_Nad_p), "subject only variable" );
		
		$bound = $runner->match( $pat2, $bind1 );
		//echo "=================\n";
		//print_r( $bound );
		//echo "=================\n";
		$this->assertEquals( $bound, array($bind_Nad_ep,$bind_Alan_ep), "subject and object variables" );
		
	}
	
	function test_supersort( ) {
		$elem1 = array( 'a' => 1, 'b'=> "bye bye" );
		$elem2 = array( 'a' => 1, 'b'=> "hello" );
		$elem3 = array( 'a' => 2, 'b'=> "aaaaa" );
		$sorted = array( $elem1, $elem2, $elem3 );
		$arr  = array( $elem3, $elem1, $elem2 );
		
		$tests = array (
						array( $elem1, $elem1,  0, "elem1 elem1" ),
						array( $elem1, $elem2, -1, "elem1 elem2" ),
						array( $elem1, $elem3, -1, "elem1 elem3" ),
						
						array( $elem2, $elem1,  1, "elem2 elem1" ),
						array( $elem2, $elem2,  0, "elem3 elem3" ),
						array( $elem2, $elem3, -1, "elem2 elem3" ),
						
						array( $elem3, $elem1,  1, "elem3 elem1" ),
						array( $elem3, $elem2,  1, "elem3 elem2" ),  
						array( $elem3, $elem3,  0, "elem3 elem3" ),
						
						);
		
		foreach ( $tests as $test ) {
			list( $v1, $v2, $expected, $mess ) = $test;
			$res = array_compare($v1, $v2);
			$res = ($res < 0) ? -1 : (($res > 0) ? 1 : 0 );
			$this->assertEquals( $res, $expected, $mess );
		}
		
		
		super_sort( $arr );
		$this->assertEquals( $arr, $sorted, "super_sort" );

	}


	function test_match_lhs( ) {
		//$rule = $this->makeTestRuleEmployment();
		$graph = $this->makeTestGraphEmployment();
		$runner = new RuleRunner($graph);
		
		list($pat1,$pat2) = $this->makeTestPatterns();
		
		$bindings = $this->makeTestBindings();
		$bind_Nad_p		=  $bindings['Nad_p'];
		$bind_Nad_e		=  $bindings['Nad_e'];
		$bind_Nad_ep	=  $bindings['Nad_ep'];
		$bind_Alan_e	=  $bindings['Alan_e'];

		
		$bound = $runner->match_lhs( array($pat1) );
		$this->assertEquals( $bound, array($bind_Nad_p), "single pattern LHS one triple" );
		
		$bound = $runner->match_lhs( array($pat2) );
		$expected = array($bind_Nad_e,$bind_Alan_e);
		super_sort($bound);
		super_sort($expected);
		$this->assertEquals( $bound, $expected, "single pattern LHS multiple triples" );
		
		$bound = $runner->match_lhs( array($pat1,$pat2) );
		//echo "=================\n";
		//print_r( $bound );
		//echo "=================\n";
		//print_r( array($bind_Nad2,$bind_Alan) );
		//echo "=================\n";
		$this->assertEquals( $bound, array($bind_Nad_ep), "two pattern LHS" );
		
	}

	function test_runOne( ) {
		//$rule = $this->makeTestRuleEmployment();
		$graph = $this->makeTestGraphEmployment();
		
		list($pat1,$pat2) = $this->makeTestPatterns();
		
		$bindings = $this->makeTestBindings();
		$bind_Nad_p		=  $bindings['Nad_p'];
		$bind_Nad_e		=  $bindings['Nad_e'];
		$bind_Nad_ep	=  $bindings['Nad_ep'];
		$bind_Alan_e	=  $bindings['Alan_e'];
		
		$rhs = array( array(
						'type' => 'triple',
						's' => 'person',
						'p' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
						'o' => 'http://xmlns.com/foaf/0.1/Person',
						's_type' => 'var',
						'p_type' => 'uri',
						'o_type' => 'uri',
						'o_datatype' => '',
						'o_lang' => '',
					)  );

		$rhs2 = array( array(
						'type' => 'triple',
						's' => 'person',
						'p' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
						'o' => 'http://www.example.com/Employee',
						's_type' => 'var',
						'p_type' => 'uri',
						'o_type' => 'uri',
						'o_datatype' => '',
						'o_lang' => '',
					)  );

		$ser = ARC2::getTurtleSerializer();
	
	
		$runner = new RuleRunner($graph);
		$runner->runOne( array($pat1), $rhs );
		$triples = $runner->inferred_triples;
		$doc = $ser->getSerializedTriples($triples);
		$expected = '@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .' . "\n" .
					'@prefix ns0: <http://xmlns.com/foaf/0.1/> .' . "\n" .
					"\n" .
					'"Nad" rdf:type ns0:Person .';
		$this->assertEquals( $doc, $expected, "single pattern LHS, single result" );
		
		
		$runner = new RuleRunner($graph);
		$runner->runOne( array($pat1,$pat2), $rhs );
		$triples = $runner->inferred_triples;
		$doc = $ser->getSerializedTriples($triples);
		$expected = '@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .' . "\n" .
					'@prefix ns0: <http://xmlns.com/foaf/0.1/> .' . "\n" .
					"\n" .
					'"Nad" rdf:type ns0:Person .';
		$this->assertEquals( $doc, $expected, "two pattern LHS, single result" );
		
		
		$runner = new RuleRunner($graph);
		$runner->runOne( array($pat2), $rhs );
		$triples = $runner->inferred_triples;
		$doc = $ser->getSerializedTriples($triples);
		$expected = '@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .' . "\n" .
					'@prefix ns0: <http://xmlns.com/foaf/0.1/> .' . "\n\n" .
					'"Nad" rdf:type ns0:Person .' . "\n\n" .
					'"Alan" rdf:type ns0:Person .';
		$this->assertEquals( $doc, $expected, "single pattern LHS, multiple triples" );
		
		
		$runner = new RuleRunner($graph);
		$runner->runOne( array($pat2), $rhs2 );
		$triples = $runner->inferred_triples;
		$doc = $ser->getSerializedTriples($triples);
		$expected = '@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .' . "\n" .
					'@prefix ns0: <http://xmlns.com/foaf/0.1/> .' . "\n" .
					'@prefix ns1: <http://www.example.com/> .' . "\n\n" .
					'"Nad" rdf:type ns1:Employee .' . "\n\n" .
					'"Alan" rdf:type ns1:Employee .';
		//echo "=================\n";
		//echo "[[".$doc."]]";
		//echo "=================\n";
		$this->assertEquals( $doc, $expected, "single pattern LHS, multiple triples (2)" );
		
		
	}

}


?>